(ns io.github.jmjoy.grpc2http.core
  (:require [immutant.web :as web]
            [mount.core :refer [defstate] :as mount]
            [clojure.string :as str]
            [clojure.core.async :as async :refer [go <! <!! timeout]])
  (:import [io.github.jmjoy.grpc2http.proto.ring
            Ring$Request Ring$Response RingHandlerGrpc]
           [io.grpc ManagedChannelBuilder]
           [java.util.concurrent TimeUnit])
  (:gen-class))

(defstate web-addr :start "127.0.0.1:8080")

(defstate grpc-addr :start "127.0.0.1:50051")

(defn addr->host&port
  [addr]
  (let [[host port] (str/split addr #":")
        port (Integer/valueOf port)]
    {:host host :port port}))

(defn handler
  ([request] (handler 0))
  ([request retry-count]
   (try (let [{:keys [host port]} (addr->host&port grpc-addr)
              channel (-> (ManagedChannelBuilder/forAddress host port)
                          (.usePlaintext true)
                          (.build))
              blockingStub (RingHandlerGrpc/newBlockingStub channel)
              {:keys [server-port server-name]} request]

          (try (-> (Ring$Request/newBuilder)
                   (.setServerPort server-port)
                   (.setServerName server-name))
               (finally (-> channel
                            (.shutdown)
                            (.awaitTermination 5 TimeUnit/SECONDS)))))

        (catch Exception e
          (if (> retry-count 5)
            (throw e)
            (do (<!! (timeout 850))
                (handler request (+ retry-count 1))))))))

(defstate web-server
  :start
  (let [{:keys [host port]} (addr->host&port web-addr)
        port (Integer/valueOf port)]
    (web/run #'handler {:host host :port port}))
  :stop (web/stop web-server))

(defn -main
  [& args]
  (mount/start))
